# 选出昨日股票
# 1. 流通盘小于80亿
# 2. 大单资金净流入为正
# 3. 换手在2 - 25%

# 今日涨幅为9个点时候全仓买入
# 明日收益为1个点以上抛出
from __future__ import division
from jqdata import *
import datetime
import tushare as ts


# 交易函数

# 一️把梭
# security_list 股票列表
# position 买入仓位
def allon_buy(security, context, position):
    order_value(security, context.portfolio.cash / position);

# 设置买入数量均摊仓位
# security 股票代码
# count 买入股票数量
# position 买入仓位 没有则为1
def average_buy(context, security, count, position):
    # 买入股票
    log.info('买入股票');

    if (position is None):
        position = 1;

    order_value(security, context.portfolio.cash);


# 根据符合条件股票数量均摊仓位
# security_list 股票列表
# position 买入仓位
def average_size_buy(security_list, context, position):

    for i in security_list:
        order_value(i, context.portfolio.cash / security_list / position);

# 卖出股票
# security 股票代码
# position 卖出仓位
def allon_sell(context, security, position):
    log.info('卖出股票');
    order_result = order_target_value(security, 0);

    if order_result is not None:
        # 因为不重复所以直接remove
        g.amount_main_and_turnover_top_list = [];
        # g.amount_main_and_turnover_top_list.remove(security);
        log.info('卖出股票 %s 完成: ' % security);
        log.info('清除昨日持仓股票数据');

# 分析函数

# 获取全部股票列表
def getAllSecurityList():
    return list(get_all_securities(['stock']).index);

def getExcludeNew(security_list, context):
    self_security_list = [];

    for security in security_list:
        start_date = get_security_info(security).start_date;
        start_datetime = datetime.datetime.strptime(str(start_date),'%Y-%m-%d')

        isNewSecurity = (context.current_dt - start_datetime).days <= 30;

        if (isNewSecurity == False):
            self_security_list.append(security);

    return self_security_list;

# 获取昨日流通市值小于80亿的股票
def getMiniMarket(security_list):
    self_security_list = [];

    for i in security_list:
        q = query(valuation).filter(valuation.code == i);
        df = get_fundamentals(q, g.yester_dt);

        if (len(df.circulating_market_cap) > 0 and df.circulating_market_cap[0] < 80):
            self_security_list.append(i);

    return self_security_list;

# 获取昨日自然跌停的股票
def getNaturalLow(security_list):
    self_security_list = [];

    for i in security_list:
        security = get_price(i, end_date = g.yester_dt, count = 1, frequency = 'daily', fields = ['open', 'close', 'low', 'high', 'paused', 'high_limit', 'low_limit']);
        securityOpen = security['open'][0]; # 开盘价
        securityClose = security['close'][0]; # 收盘价
        securityHigh = security['high'][0]; # 最高价
        securityLow = security['low'][0]; # 最低价
        securityHighLimit = security['high_limit'][0]; # 涨停价
        securityLowLimit = security['low_limit'][0]; # 涨停价
        securityPaused = security['paused'][0]; # 停牌天数

        # 自然跌停
        # 1.最高价非跌停价
        # 2.收盘价跌停

        #  同时 开盘价不等于最低价 收盘价等于最高价 同时 最底价等于跌停价 同时没有停牌的
        if (
            # 开盘价不等于收盘价
            securityOpen != securityClose and

            # 收盘价等于最低价
            securityClose == securityLow and

            # 最低价等于跌停价
            securityLow == securityLowLimit and

            # 同时没有停牌的
            securityPaused == 0):

            # 保存当天开盘到涨停的涨幅
            g.max_rose[i] = (securityClose / securityOpen);
            self_security_list.append(i);

    return self_security_list;

# 获取昨日自然涨停的股票
def getNaturalHigh(security_list):
    self_security_list = [];

    for i in security_list:
        security = get_price(i, end_date = g.yester_dt, count = 1, frequency = 'daily', fields = ['open', 'close', 'low', 'high', 'paused', 'high_limit', 'low_limit']);
        securityOpen = security['open'][0]; # 开盘价
        securityClose = security['close'][0]; # 收盘价
        securityHigh = security['high'][0]; # 最高价
        securityLow = security['low'][0]; # 最低价
        securityHighLimit = security['high_limit'][0]; # 涨停价
        securityPaused = security['paused'][0]; # 停牌天数

        # 自然涨停
        # 1.最低价非涨停价
        # 2.收盘价涨停

        # 开盘价不等于收盘价 同时 开盘价不等于最低价 收盘价等于最高价 同时 最高价等于涨停价 同时没有停牌的
        if (securityOpen != securityClose and
            (securityClose / securityOpen) < 1.19 and
            securityClose == securityHigh and
            securityHigh == securityHighLimit and
            securityPaused == 0):

            # 保存当天开盘到涨停的涨幅
            g.max_rose[i] = (securityClose / securityOpen);
            self_security_list.append(i);

    return self_security_list;

# 获取昨日换手率靠前/靠后的涨停股票
def getTurnoverRadioTop(security_top_list):
    self_security_list = [];
    self_list = {};

    for i in security_top_list:
        q = query(valuation).filter(valuation.code == i);
        df = get_fundamentals(q, g.yester_dt);

        if (df.dropna().empty == False):

            if (df['turnover_ratio'][0] > 2 and df['turnover_ratio'][0] < 25):
                self_list[i] = df['turnover_ratio'][0];

    self_list = sorted(self_list.items(), key=lambda d:d[1]);

    for i in self_list:
        self_security_list.append(i[0]);

    self_security_list.reverse();
    return self_security_list;

# 获取昨日大单流入靠前/靠后的股票
def getAmountMain(context, security_list, count, isTop):
    index = count;
    # 保存净流入的
    money_buy_list = [];
    # 保存净流出的
    money_order_list = [];

    if (len(g.money_flow_df) == 0):
        g.money_flow_df = get_money_flow(security_list, end_date = g.yester_dt, fields = ['sec_code', 'date', 'change_pct', 'net_amount_main'], count = 1);

    money_buy_list = g.money_flow_df[g.money_flow_df.net_amount_main > 0];
    money_order_list = g.money_flow_df[g.money_flow_df.net_amount_main < 0];

    self_list = list(g.money_flow_df.sort(columns='net_amount_main').sec_code);

    if (isTop == True):
        money_flow_df_bottom = list(money_order_list.sort(columns='net_amount_main').sec_code);
        g.money_flow_df_bottom_list.append(money_flow_df_bottom);
        return money_flow_df_bottom;
    else:
        money_flow_df_top = list(money_buy_list.sort(columns='net_amount_main').sec_code);
        money_flow_df_top.reverse();
        g.money_flow_df_top_list.append(money_flow_df_top);
        return money_flow_df_top;

# 获取换手率 大单流入综合排名考前的数据 isTurnover True 换手率靠前 False 大单流入靠前
def getByAmountMainAndturnoverTop(turnover_top_security_high_list, amount_main_buy_security_list, isTurnover, count):
    result_list = [];

    if (isTurnover == True):

        for i in turnover_top_security_high_list:

            # 判断大单流入名单内是否有该换手率股票 如果有则加入
            if (i in amount_main_buy_security_list):
                result_list.append(i);

    else:

        for i in amount_main_buy_security_list:

            # 判断大单流入名单内是否有该换手率股票 如果有则加入
            if (i in turnover_top_security_high_list):
                result_list.append(i);

    return result_list[0:count];

# 聚宽初始化函数
def initialize(context):
    g.money_flow_df_bottom_list = [];
    g.money_flow_df_top_list = [];
    g.max_rose = {};
    g.amount_main_and_turnover_top_list = [];

    set_benchmark('000001.XSHG');

# 每个时间段执行
def handle_data(context, data):

    # 获取当前时间数据
    current_data = get_current_data();

    if (len(g.amount_main_and_turnover_top_list) > 0):

        for security in g.amount_main_and_turnover_top_list:

        # security = g.amount_main_and_turnover_top_list[0];

            # 排除st
            if (current_data[security].is_st == False):
                g.last_df = history(1,'1d','close',[security]);

                # 得到当前价格
                price = data[security].close;

                # 获取这只股票昨天收盘价
                last_close = g.last_df[security][0];

                # 获取持仓成本
                avg_cost = context.portfolio.positions[security].avg_cost;

                # 获取当前价格
                price1 = context.portfolio.positions[security].price;

                # log.info('股票 %s %s 达到涨跌幅: %s ' % (security, context.current_dt, (price / last_close)));

                if (price1 != 0 and avg_cost != 0):
                    profit = price1 / avg_cost;
                else:
                    profit = 0;

                # 涨幅9个点以上买入
                if (price != last_close and (price / last_close) > 1.02 and avg_cost == 0):
                    log.info('%s 持仓成本 %s ' % (security, avg_cost));
                    log.info('%s 昨日收盘价 %s' % (security, last_close));
                    log.info('%s 当前价格 %s ' % (security, price));
                    average_buy(context, security, 1, 1);

                # 收益1%止盈
                elif (price1 != 0 and avg_cost != 0 and profit >= 1.09):
                    log.info('收益 %s 个点止盈' % ((profit - 1) * 100));
                    allon_sell(context, security, 1);

                # 亏损10%止损
                elif (price1 != 0 and avg_cost != 0 and profit <= 0.90):
                    log.info('亏损 %s 个点止损' % ((1 - profit) * 100));
                    allon_sell(context, security, 1);

def after_trading_end(context):
    # log.info('收盘');

    if (len(g.amount_main_and_turnover_top_list) > 0):
        security = g.amount_main_and_turnover_top_list[0];

        if (context.portfolio.positions[security].avg_cost == 0):
            g.amount_main_and_turnover_top_list = [];

def before_trading_start(context):

    # 获取昨日时间
    g.yester_dt = context.current_dt + datetime.timedelta(days = -1);

    # 每日开盘清除昨日数据
    g.max_rose = {};
    g.money_flow_df = [];

    # 如果没有持仓股票才使用最新获取的数据
    if (len(g.amount_main_and_turnover_top_list) == 0):
        log.info('数据时间');
        log.info(g.yester_dt);

        # 获取昨日所有股票
        security_list = getAllSecurityList();

        # 获取昨日自然涨停的股票
        security_high_list = getNaturalHigh(security_list);

        security_list1 = getMiniMarket(security_high_list);

        # log.info('昨日流通市值小于80亿的股票数量: %s ' % len(security_list1));

        # 获取换手率大于2 同时 小于25的股票 (排除次新股开板)
        security_turnover_top_list = getTurnoverRadioTop(security_list1);

        # log.info('昨日流通市值小于80亿 同时换手 小于25 and 大于2 的股票数量: %s ' % len(security_turnover_top_list));

        # 获取跌停中大单流入靠前的股票
        amount_main_buy_list = getAmountMain(context, security_turnover_top_list, len(security_turnover_top_list), False);

        # log.info('今日备选股票 昨日大单流入 流通市值小于80亿 换手 小于25 and 大于2 的股票数量: %s ' % len(amount_main_buy_list));

        g.amount_main_and_turnover_top_list = amount_main_buy_list;
    else:
        log.info(g.amount_main_and_turnover_top_list);
